package com.quyunshuo.module.home.activity.report

import androidx.lifecycle.viewModelScope
import com.quyunshuo.edwingoal.base.mvvm.vm.BaseViewModel
import com.quyunshuo.module.home.room.entity.Steps
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject

/**
 * 步数报告页面的 ViewModel
 *
 * 主要职责：
 * 1. 管理步数数据的获取和存储
 * 2. 处理步数数据的导航（上一项/下一项）
 * 3. 维护页面状态（当前位置、列表大小、按钮状态等）
 *
 * @property mRepository ReportRepository 仓库层，通过Hilt注入
 *
 * @author Qu Yunshuo
 * @since 5/25/21 5:41 PM
 */
@HiltViewModel
class ReportViewModel @Inject constructor(
    private val mRepository: ReportRepository
) : BaseViewModel() {

    // region 状态管理
    // =================================================================

    /**
     * 当前选中的步数数据
     *
     * 特性：
     * - 初始值为 null
     * - 当数据加载完成后自动设置为第一项
     * - 用户导航时会更新此值
     */
    private val _currentStep = MutableStateFlow<Steps?>(null)
    val currentStep: StateFlow<Steps?> = _currentStep.asStateFlow()

    /**
     * 当前选中的步数在列表中的位置
     *
     * 特性：
     * - 初始值为 0
     * - 范围在 0 到 (列表大小-1) 之间
     * - 用于跟踪用户当前浏览的位置
     */
    private val _stepPosition = MutableStateFlow(0)
    val stepPosition: StateFlow<Int> = _stepPosition.asStateFlow()

    /**
     * 步数列表的大小
     *
     * 特性：
     * - 初始值为 0
     * - 当数据加载完成后更新为实际列表大小
     * - 用于边界检查和状态管理
     */
    private val _stepListSize = MutableStateFlow(0)
    val stepListSize: StateFlow<Int> = _stepListSize.asStateFlow()

    /**
     * 是否显示"上一项"按钮
     *
     * 特性：
     * - 初始值为 false
     * - 当当前位置 > 0 时为 true
     * - 用于控制UI按钮的可见性
     */
    private val _hasPrevious = MutableStateFlow(false)
    val hasPrevious: StateFlow<Boolean> = _hasPrevious.asStateFlow()

    /**
     * 是否显示"下一项"按钮
     *
     * 特性：
     * - 初始值为 false
     * - 当当前位置 < 列表大小-1 时为 true
     * - 用于控制UI按钮的可见性
     */
    private val _hasNext = MutableStateFlow(false)
    val hasNext: StateFlow<Boolean> = _hasNext.asStateFlow()

    /**
     * 数据是否为空
     *
     * 特性：
     * - 初始值为 false
     * - 当数据加载完成后，如果列表为空则为 true
     * - 用于显示空数据状态
     */
    private val _isEmpty = MutableStateFlow(false)
    val isEmpty: StateFlow<Boolean> = _isEmpty.asStateFlow()
    // endregion

    // region 数据流
    // =================================================================

    /**
     * 所有步数数据流
     *
     * 特性：
     * - 使用 stateIn 转换为 StateFlow
     * - 当有订阅者时自动开始收集数据
     * - 最后一个订阅者取消订阅后保持5秒活跃状态
     * - 初始值为空列表
     */
    val allStep = mRepository.queryAll()
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = emptyList()
        )
    // endregion

    // region 初始化
    // =================================================================

    init {
        // 监听步数数据流的变化
        viewModelScope.launch {
            allStep.collect { list ->
                // 更新列表大小状态
                _stepListSize.value = list.size

                // 更新空数据状态
                _isEmpty.value = list.isEmpty()

                /**
                 * 自动选择第一项的条件：
                 * 1. 列表不为空
                 * 2. 当前没有选中的步数数据（初始状态）
                 */
                if (list.isNotEmpty() && _currentStep.value == null) {
                    updateDayStepPosition(0)
                }
            }
        }
    }
    // endregion

    // region 公共方法
    // =================================================================

    /**
     * 更新当前选中的步数位置
     *
     * @param position 要选择的位置索引
     *
     * 处理逻辑：
     * 1. 检查位置是否在有效范围内（0 ≤ position < list.size）
     * 2. 更新当前位置状态
     * 3. 更新当前步数数据状态
     * 4. 更新按钮状态（是否有上一项/下一项）
     */
    fun updateDayStepPosition(position: Int) {
        viewModelScope.launch {
            val list = allStep.value
            // 确保位置在有效范围内
            if (position in 0 until list.size) {
                // 更新位置状态
                _stepPosition.value = position

                // 更新当前步数数据
                _currentStep.value = list[position]

                // 更新按钮状态
                _hasPrevious.value = position > 0
                _hasNext.value = position < list.lastIndex
            }
        }
    }

    /**
     * 导航到上一项
     *
     * 处理逻辑：
     * 1. 检查当前位置是否大于0
     * 2. 如果是，则更新位置为当前位置减1
     */
    fun previousStep() {
        val current = stepPosition.value
        if (current > 0) updateDayStepPosition(current - 1)
    }

    /**
     * 导航到下一项
     *
     * 处理逻辑：
     * 1. 检查当前位置是否小于列表大小减1
     * 2. 如果是，则更新位置为当前位置加1
     */
    fun nextStep() {
        val current = stepPosition.value
        if (current < stepListSize.value - 1) updateDayStepPosition(current + 1)
    }
    // endregion
}

/*
结论：

    •

    当你使用StateFlow时，使用value属性来读取和设置值。
    •

    当你使用SharedFlow时，使用emit（在协程中）或tryEmit（非协程）来发射事件。
    •

    当你构建普通Flow时，在flow { ... }构建器中使用emit。
 */